#pragma once
#include <Windows.h>
#include <string>
#include <map>
#include <vector>
#include <functional>

#define MC_NOKEY		0x00
#define MC_KEY_DOWN		0x02
#define MC_KEY_PRESSED	0x04
#define MC_KEY_RELEASED 0x08

#define MC_KEY0 1
#define MC_KEY1 2
#define MC_KEY2 3
#define MC_KEY3 4
#define MC_KEY4 5
#define MC_KEY5 6
#define MC_KEY6 7
#define MC_KEY7 8
#define MC_KEY8 9
#define MC_KEY9 10

#define MC_KEY_A 11
#define MC_KEY_B 12
#define MC_KEY_C 14
#define MC_KEY_D 13
#define MC_KEY_E 15
#define MC_KEY_F 16
#define MC_KEY_G 17
#define MC_KEY_H 18
#define MC_KEY_I 19
#define MC_KEY_J 20
#define MC_KEY_K 21
#define MC_KEY_L 22
#define MC_KEY_M 23
#define MC_KEY_N 24
#define MC_KEY_O 25
#define MC_KEY_P 26
#define MC_KEY_Q 27
#define MC_KEY_R 28
#define MC_KEY_S 29
#define MC_KEY_T 30
#define MC_KEY_U 31
#define MC_KEY_V 32
#define MC_KEY_W 33
#define MC_KEY_X 34
#define MC_KEY_Y 35
#define MC_KEY_Z 36

#define MC_F1	37
#define MC_F2	38
#define MC_F3	39
#define MC_F4	40
#define MC_F5	41
#define MC_F6	42
#define MC_F7	43
#define MC_F8	44
#define MC_F9	45
#define MC_F10	46
#define MC_F11	47
#define MC_F12	48

#define MC_BACKSPACE	49
#define MC_SPACE		50
#define MC_BACKTICK		51
#define MC_ENTER		52
#define MC_RETURN		MC_ENTER
#define MC_CAPSLOCK		53
#define MC_TAB			54
#define MC_LSHIFT		55
#define MC_RSHIFT		56
#define MC_LCONTROL		57
#define MC_RCONTROL		58
#define MC_ALT			59
#define MC_OPTION		60
#define MC_UP			61
#define MC_DOWN			62
#define MC_RIGHT		63
#define MC_LEFT			64

#define MC_MINUS		65
#define MC_EQUALS		66
#define MC_COMMA		67
#define MC_PERIOD		68
#define MC_SEMICOLON	69
#define MC_TICK			70
#define MC_SQUARE_BRACKET_RIGHT 71
#define MC_SQUARE_BRACKET_LEFT	72
#define MC_BACKSLASH	73
#define MC_SLASH		74

struct KeyEvt
{
	char	key			= MC_NOKEY;
	int		code		= MC_NOKEY;
	int		event_type	= MC_NOKEY;
};

class Keyboard
{
public:
	// Initialized state
	static bool IsInitialized() { return _init_status; }
	
	// Initializes keyboard input polling thread
	static void Initialize();

	// Stops the thread that polls key events
	static void Shutdown();

	// Gets the state of a key (whether it is down or not)
	static bool IsKeyDown(int key);

	// Gets state of key after last keyboard event (slower than IsKeyDown)
	static bool IsKeyPressed(int key);

	// Gets whether the key was released after last event
	static bool IsKeyReleased(int key);

	static void SimulateKeypress(int key);
	static void SimulateKeypressSequence(std::string msg);
	static void SimulateKeypressSequence(std::wstring msg);
	static void SimulateKeypressSequence(char* msg);

	static void SimulateKeypressWithShift(int key);
	static void SimulateKeypressSequenceWithShift(std::string msg);
	static void SimulateKeypressSequenceWithShift(std::wstring msg);
	static void SimulateKeypressSequenceWithShift(char* msg);
	
	// Force checking keyboard events
	static void PollEvents();

	// Gets the state of the key
	static int GetKeyState(int _key);

	// converts character code to an ASCII character
	static char ToChar(int _key);

	// converts monochrome character code to ascii virtual code
	static int GetVirtualKeyCode(int _key);

	static char GetKeyValue(int _key, bool _capital, bool _caps_lock_enabled);

private:
	static int GetKeyCode(char key);
	static bool _init_status;
	static long long _pressed_time;
	static size_t _default_key_hold_time;
	static size_t _pressed_key_hold_time;
	static std::map<int, int> _Key_Code_Bindings;
	static std::vector<int> _Key_States;
	static std::vector<size_t> _Key_Hold_Times;

	// used for retreiving character versions when shift is pressed or caps lock is on
	static std::map<int, std::pair<char, char>> _Key_Capital_Bindings;
};
